<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\messaging\service;

interface IPostmark
{
  public function setReceiver($sReceiver);
  public function setReceiverFromContact(\crcl\base\messaging\contact\IConcrete $oContact);
  public function getReceiver();

  public function send(\crcl\base\messaging\message\IMail $oMail);
}

class ContainerPostmark extends Concrete implements IConcrete, IPostmark
{
  const ENDPOINT = 'https://api.postmarkapp.com/email';

  public function setReceiver($sReceiver)
  {
    $this->sReceiver = $sReceiver;
    return $this;
  }

  public function setReceiverFromContact(\crcl\base\messaging\contact\IConcrete $oContact)
  {
    $this->sReceiver = $oContact->toMail();
    return $this;
  }

  public function getReceiver()
  {
    return $this->sReceiver;
  }

  public function getSender()
  {
    $sName = $this->oUri->getUser();
    $sMail = $this->oUri->getPassword();
    $sSender = '"' . $sName . '" <' . $sMail . '>';

    return $sSender;
  }

  public function send(\crcl\base\messaging\message\IMail $oMail)
  {
    $sMessage = $this->composeMessage($oMail);
    $sToken = $this->getApiToken();

    $aHeaders = $this->composeHeaders($sToken);

    $oRequest = \curl_init();
    \curl_setopt($oRequest, \CURLOPT_URL, self::ENDPOINT);
    \curl_setopt($oRequest, \CURLOPT_RETURNTRANSFER, TRUE);
    \curl_setopt($oRequest, \CURLOPT_CUSTOMREQUEST, 'POST');
    \curl_setopt($oRequest, \CURLOPT_POSTFIELDS, $sMessage);
    \curl_setopt($oRequest, \CURLOPT_HTTPHEADER, $aHeaders);
    \curl_setopt($oRequest, \CURLOPT_SSL_VERIFYPEER, TRUE);
    \curl_setopt($oRequest, \CURLOPT_SSL_VERIFYHOST, 2);
    \curl_setopt($oRequest, \CURLOPT_CAINFO, \crcl\base\base\Path::getDirCerts() . 'cacert.pem');

    $sReturn = \curl_exec($oRequest);
    $sCurlError = \curl_error($oRequest);
    $iHttpCode = \curl_getinfo($oRequest, \CURLINFO_HTTP_CODE);

    try
    {
      $this->checkCurl($sCurlError);
      $this->checkHttpCode($iHttpCode, $sReturn);
      return \TRUE;
    }
    catch (\Exception $e)
    {
      if ($e instanceof \crcl\base\Exception)
      {
        $aCauses = $e->getCauses();
        $aCauses->add('oMail', $oMail);
        $aCauses->add('aHeaders', $aHeaders);
        $aCauses->add('sReturn', $sReturn);
      }
      else
      {
        $aCauses = array();
        $aCauses['oMail'] = $oMail;
        $aCauses['aHeaders'] = $aHeaders;
        $aCauses['sReturn'] = $sReturn;
      }

      $e->setCauses($aCauses);
      throw $e;
    }
  }

  /** PRIVATE *************************************************************************************/

  private $sReceiver;

  private function getApiToken()
  {
    return $this->oUri->getAuthority();
  }

  private function composeMessage(\crcl\base\messaging\message\IMail $oMail)
  {
    $aData = array();
    $aData['From']        = $this->getSender();
    $aData['To']          = $this->getReceiver();
    $aData['Subject']     = $oMail->getSubject();
    $aData['TextBody']    = $oMail->getText();
    if ($oMail->hasHtml())
    {
      $aData['HtmlBody']    = $oMail->getHtml();
    }

    $sData = \json_encode($aData);
    return $sData;

//    $aData['Attachments'] = $oMessage->getAttachments();

    //TODO
    //$aData['Bcc']         = 'as@crcl.de';

//    $aData['Cc']       = array();

//    $aData['Cc']   = $oMessage->getReceiverCc();
//    $aData['Bcc']  = $oMessage->getReceiverBcc();
//    $aData['Subject'] = $oMessage->getSubject();
//    $aData['Tag'] = $oMessage->getTag();

//    $aData['ReplyTo'] = $oMessage->getReplyTo();
//    $aData['Headers'] = $oMessage->getHeaders();
  }

  private function composeHeaders($sToken)
  {
    $aHeaders = array(
      'Accept: application/json',
      'Content-Type: application/json',
      'X-Postmark-Server-Token: ' . $sToken);
    return $aHeaders;
  }

  private function checkCurl($sError)
  {
    if ($sError !== '')
    {
      throw new Exception($sError);
    }
  }

  private function checkHttpCode($iHttpCode, $sReturn)
  {
    $oReturn = FALSE;
    if (\strlen($sReturn))
    {
      $oReturn = \json_decode($sReturn);
    }

    if ($iHttpCode !== 200)
    {
      switch ($iHttpCode)
      {
        case 401:
          $sMessage = 'Unauthorized.';
          $sDescription = 'Missing or incorrect API Key header.';
          break;
        case 422:
          $sMessage = 'Unprocessable Entity.';
          $sDescription = 'Something with the message is not quite right (either malformed JSON or incorrect fields).';
          break;
        case 500:
          $sMessage = 'Internal Server Error.';
          $sDescription = 'Postmark internal error.';
          break;
        default:
          $sMessage = 'Unknown error.';
          $sDescription = 'No description available.';
      }
      $aCauses = array();
      $aCauses['sDescription'] = $sDescription;
      if ($oReturn)
      {
        $aCauses['sMessage'] = $oReturn->Message;
        $aCauses['iError'] = $oReturn->ErrorCode;
      }

      throw new Exception($sMessage, Exception::ERROR_API, $aCauses, $iHttpCode);
    }
  }

}